class ParrotClient {
    constructor(module) {
        this.module = module
        this.ms_code = ""
        this.ms_name = ""
        this.__url = ""
        this.__timestamp = ""
        this.__username = ""
        this.__password = ""
        this.ready = false
        this.rec_buf_ptr = 0
        this.__open_issued = 0
        this._events = {}

        this.init()
    }

    init() {
        this.rec_buf_ptr = this.module._malloc(320)

        this.client = this.module._parrot_get_client()

        let ptr = this.module.addFunction(this.handleEvent.bind(this), "vi")
        this.module._parrot_set_event_callback(this.client, ptr)

        // this.module._parrot_enable_builtin_sink(this.client)

        ptr = this.module.addFunction(this.playFrame.bind(this), "vii")
        this.module._parrot_set_play_callback(this.client, ptr)


        this.ready = true
        this.setLogLevel(0)
        this.__try_connect()
    }

    __on(event, callback, once) {
        let callbacks = this._events[event] || []
        callbacks.push({
            callback: callback, once: once,
        })
        this._events[event] = callbacks
    }

    on(event, callback) {
        this.__on(event, callback, false)
    }

    once(event, callback) {
        this.__on(event, callback, true)
    }

    off(event) {
        delete this._events[event]
    }

    emit(event, data) {
        let callbacks = this._events[event]
        if (!callbacks || callbacks.length === 0) return

        this._events[event] = callbacks.filter(entry => {
            entry.callback(event, data)
            return !entry.once
        })
    }

    playFrame(ptr, length) {
        const buf = new Uint8Array(length)
        for (let i = 0; i < length; i++) {
            buf[i] = this.module.HEAPU8[ptr + i]
        }

        this.emit('playFrame', buf)
    }

    handleEvent(json) {
        const str = this.module.UTF8ToString(json)
        const event = JSON.parse(str)
        console.info(event)
        this.emit(event.event, event.data)
    }

    sendFrame(buffer) {
        const bytes = new Uint8Array(buffer)
        this.module.HEAP8.set(bytes, this.rec_buf_ptr)

        this.module._parrot_send_frame(this.client, this.rec_buf_ptr, buffer.byteLength)
    }

    setLogLevel(level) {
        this.module._parrot_set_loglevel(this.client, level)
    }

    openParrot() {
        this.__open_issued = true
        this.__try_connect()
    }

    closeParrot() {
        this.__open_issued = false;
        this.module._parrot_close(this.client)
    }

    setUrl(url) {
        if (this.__url === url) return

        const fields = url.split('/')
        const http_url = {
            'wss:': 'https:',
            'ws:': 'http:',
        }[fields[0]] + "//" + fields[2] + "/v1/customer/checklogin";
        fetch(http_url).then(r => r)

        this.__url = url
        this.__try_connect()
    }

    setUsername(username) {
        if (this.__username === username) return
        this.__username = username
        this.__try_connect()
    }

    setPassword(password) {
        if (this.__password === password) return
        this.__password = password
        this.__try_connect()
    }

    setTimestamp(timestamp) {
        if (this.__timestamp === timestamp) return
        this.__timestamp = timestamp
        this.__try_connect()
    }

    __try_connect() {
        if (this.ready && this.__open_issued
            && this.__timestamp && this.__url && this.__username && this.__password) {
            this.__set_url(this.__url)
            this.__set_username(this.__username)
            this.__set_timestamp(this.__timestamp)
            this.__set_password(this.__password)
            this.__open()
            console.info("real open poc")
        } else {
            console.warn("parameter not complete", this)
        }
    }

    __set_url(url) {
        const ptr = this.module.allocateUTF8(url)
        this.module._parrot_set_url(this.client, ptr)
        this.module._free(ptr)
    }

    __set_timestamp(timestamp) {
        const ptr = this.module.allocateUTF8(timestamp)
        this.module._parrot_set_timestamp(this.client, ptr)
        this.module._free(ptr)
    }

    __set_username(username) {
        this.ms_code = username

        const ptr = this.module.allocateUTF8(username)
        this.module._parrot_set_username(this.client, ptr)
        this.module._free(ptr)
    }

    __set_password(password) {
        const ptr = this.module.allocateUTF8(password)
        this.module._parrot_set_password(this.client, ptr)
        this.module._free(ptr)
    }

    __open() {
        console.info("poc_open")
        this.module._parrot_open(this.client)
    }

    startLiveCast(ids) {
        if (!Array.isArray(ids)) {
            console.error('parameter is not array')
            return;
        }

        const nonString = ids.filter(id => typeof (id) != 'number')
        if (nonString.length > 0) {
            console.error('parameter contains non-string')
            return;
        }

        const ptr = this.module._malloc(4 * ids.length)
        for (let i = 0; i < ids.length; i++) {
            this.module.setValue(ptr + i * 4, ids[i], 'i32')
        }

        this.module._parrot_start_live_cast(this.client, ptr, ids.length)
        this.module._free(ptr)
    }

    stopLiveCast() {
        this.module._parrot_stop_live_cast(this.client)
    }

    duplexCall(callee) {
        const ptr = this.module.allocateUTF8(callee)
        this.module._parrot_duplex_call(this.client, ptr)
        this.module._free(ptr)
    }

    duplexBye() {
        this.module._parrot_duplex_bye(this.client)
    }

    duplexAnswer(code) {
        this.module._parrot_duplex_answer(this.client, code)
    }

}

window.ParrotClient = ParrotClient;
